package com.smarthome.ipc.aopu;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.smarthome.domain.ipc.IpcCodeEnum;
import com.smarthome.domain.ipc.IpcConstants;
import com.smarthome.domain.ipc.req.AopuIpcResidenceDoorStatusRequest;
import com.smarthome.domain.ipc.req.IpcLogRecordRequest;
import com.smarthome.ipc.IpcClientMain;

public class AopuTcpCorrespondence {
	private static final Logger LOGGER = LoggerFactory.getLogger(AopuTcpCorrespondence.class);
	private final static String PRE_LOGGER = "[AopuTcpCorrespondence]";

	private static Socket socket = null;

	private static int execNum = 0;

	/**
	 * 保持连接 ,接收设备传送的信息并给出响应.
	 * 
	 * @param command
	 * @throws Exception
	 */
	public static void receiveCommand() {
		byte doorNum = 0x01;
		try {
			// 1.保持socket连接
//			aliveSocket();

			// 2.获取设备状态信息
			OutputStream outputStream = socket.getOutputStream();
			InputStream is = socket.getInputStream();
			byte[] byes = new byte[36];
			is.read(byes);
			if (byes[2] == AopuTcpConstans.COMMAND_KEEP_CONN) {
				LOGGER.info(PRE_LOGGER + "接收指令：" + byte2hex(byes));

				// 3.获取摆闸状态
				byte statusByte = byes[14];
				Map<String, Boolean> doorss = new HashMap<String, Boolean>();

				byte tmps1 = (byte) (statusByte ^ 0x01);// 1号门
				doorss.put("1", false);
				if (tmps1 > 0) {
					doorss.put("1", true);
				}
				byte tmps2 = (byte) (statusByte ^ 0x02);// 2号门
				doorss.put("2", false);
				if (tmps2 > 0) {
					doorss.put("2", true);
				}
				byte tmps3 = (byte) (statusByte ^ 0x04);// 3号门
				doorss.put("3", false);
				if (tmps3 > 0) {
					doorss.put("3", true);
				}
				byte tmps4 = (byte) (statusByte ^ 0x08);// 4号门
				doorss.put("4", false);
				if (tmps4 > 0) {
					doorss.put("4", true);
				}
				// 4.发送状态信息
				AopuIpcResidenceDoorStatusRequest requestrtn = new AopuIpcResidenceDoorStatusRequest();
				requestrtn.setCommand(IpcConstants.IPC_COMMAND_RESIDENCE_DOOR_AOPU_STATUS);
				requestrtn.setDoorss(doorss);
				try {
					IpcClientMain.getInstance().sendCommand(requestrtn);
				} catch (Exception e1) {
					// TODO Auto-generated catch block
					LOGGER.info(PRE_LOGGER + "奥普控制器获取小区摆闸状态后，向云平台推送状态信息产生异常！" + e1.getMessage());
				}

				// 5.做出回应以保持连接
				byte lengthL = 0x00;
				byte lengthH = 0x00;
				byte[] data = {};
				byte[] headbytes = getHead(AopuTcpConstans.COMMAND_KEEP_CONN, doorNum, lengthL, lengthH, data);
				byte[] tailbytes = getTail(headbytes);
				outputStream.write(headbytes);
				outputStream.write(tailbytes);
				outputStream.flush();
				LOGGER.info(PRE_LOGGER + "发送指令：" + byte2hex(headbytes) + byte2hex(tailbytes));
			}
			is.close();
		} catch (Exception e) {
			LOGGER.info(PRE_LOGGER + "心跳异常!,具体信息为[" + e + "]");
			IpcLogRecordRequest requestrtn = new IpcLogRecordRequest();
			requestrtn.setCommand(IpcConstants.IPC_COMMAND_LOG_RECORD);
			requestrtn.setCmd(String.valueOf(AopuTcpConstans.COMMAND_KEEP_CONN));
			requestrtn.setContent(e.getMessage());
			requestrtn.setRemark("奥普设备保持心跳产生异常");
			requestrtn.setFailTimes(0);
			requestrtn.setRtnCode(IpcCodeEnum.SYSTEM_ERROR.getCode());
			requestrtn.setSn(String.valueOf(doorNum));
			try {
				IpcClientMain.getInstance().sendCommand(requestrtn);
			} catch (Exception e1) {
				// TODO Auto-generated catch block
				LOGGER.info(PRE_LOGGER + "保持心跳失败后，向云平台推送错误日志产生异常！" + e.getMessage());
			}
		}
	}

	/**
	 * 执行操作类指令
	 * 
	 * @param command
	 * @throws Exception
	 */
	public static void doCommand(byte command, byte doorNum, byte lengthL, byte lengthH, byte[] data, String ip,int port)
			throws Exception {

		try {
			// 1.执行次数检查
			if (execNum > AopuTcpConstans.EXEC_COMMOND_MAX_NUM) {
				LOGGER.info(PRE_LOGGER + "命令[" + command + "]已重复执行=" + execNum + "=次,超过系统设定的次数限制.请联系设备管理员排查问题!");
				return;
			}
			execNum += 1;

			// 2.保持socket连接
			aliveSocket(ip,port);

			// 3.执行指令
			byte[] headbytes = getHead(command, doorNum, lengthL, lengthH, data);
			byte[] tailbytes = getTail(headbytes);
			OutputStream outputStream = socket.getOutputStream();
			InputStream is = socket.getInputStream();
			outputStream.write(headbytes);
			outputStream.write(tailbytes);
			outputStream.flush();
			LOGGER.info(PRE_LOGGER + "第=" + execNum + "=次执行命令[" + byte2hex(headbytes) + byte2hex(tailbytes) + "]开始.");

			// 4.获取指令结果
			byte[] byes = new byte[10];
			is.read(byes);
			LOGGER.info(PRE_LOGGER + "第=" + execNum + "=次执行命令返回结果[" + byte2hex(byes) + "]");
			if (!Integer.toHexString(byes[7]).equals("6")) {
				LOGGER.info(PRE_LOGGER + "命令执行失败!重新执行一次命令。");
				socket.close();
				doCommand(command, doorNum, lengthL, lengthH, data, ip,port);
			}
			is.close();
			LOGGER.info(PRE_LOGGER + "第=" + execNum + "=次执行命令[" + byte2hex(headbytes) + byte2hex(tailbytes) + "]结束.");

			// 5.将执行次数清零
			execNum = 0;
		} catch (Exception e) {
			LOGGER.info(PRE_LOGGER + "命令执行异常!具体信息为[" + e + "],重新执行一次命令。");
			socket.close();
			doCommand(command, doorNum, lengthL, lengthH, data, ip,port);
		}
	}

	/**
	 * 获取指令头
	 * 
	 * @param command
	 * @param doorNum
	 * @param lengthL
	 * @param lengthH
	 * @return
	 */
	private static byte[] getHead(byte command, byte doorNum, byte lengthL, byte lengthH, byte[] data) {
		byte[] headbytes = new byte[7 + data.length];
		headbytes[0] = AopuTcpConstans.PACKAGE_HEND_STX;
		byte[] rand = new byte[1];
		new Random().nextBytes(rand);
		headbytes[1] = rand[0];
		headbytes[2] = command;
		headbytes[3] = AopuTcpConstans.PACKAGE_HEND_ADDRESS;
		headbytes[4] = doorNum;
		headbytes[5] = lengthL;
		headbytes[6] = lengthH;
		for (int i = 0, j = 7; i < data.length; i++, j++) {
			headbytes[j] = data[0];
		}
		return headbytes;
	}

	/**
	 * 获取指令尾
	 * 
	 * @param headbytes
	 * @return
	 */
	private static byte[] getTail(byte[] headbytes) {
		byte csbit;
		csbit = headbytes[0];
		for (int i = 1; i < headbytes.length; i++) {
			csbit = (byte) (csbit ^ headbytes[i]);
		}
		byte[] tailbytes = new byte[2];
		tailbytes[0] = csbit;
		tailbytes[1] = AopuTcpConstans.PACKAGE_TAIL_ETX;
		return tailbytes;
	}

	/**
	 * 保持socket连接有效
	 * 
	 * @throws UnknownHostException
	 * @throws IOException
	 */
	private static void aliveSocket(String ip,int port) throws UnknownHostException, IOException {
		if (socket == null || socket.isClosed()) {
			socket = new Socket(ip, port);
		}
		socket.setKeepAlive(true);
		socket.setSoTimeout(0);
		// socket.sendUrgentData(0xff);
	}

	/**
	 * 打印显示指令（十六进制）
	 * 
	 * @param buffer
	 * @return
	 */
	private static String byte2hex(byte[] buffer) {
		String h = "";

		for (int i = 0; i < buffer.length; i++) {
			String temp = Integer.toHexString(buffer[i] & 0xFF);
			if (temp.length() == 1) {
				temp = "0" + temp;
			}
			h = h + " " + temp;
		}
		return h.toUpperCase();
	}

}
